<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script>
    // * 在JavaScript中，`call`、`apply`和`bind`是`Function`对象自带的三个方法。
    // function fn(){
    //
    // }
    //
    // console.log(fn.__proto__ === Function.prototype)
    //
    // const obj = {
    //
    // }
    // console.log(obj.__proto__ === Object.prototype);


    // * call()、apply()、bind() 都是用来重定义 this 这个对象的！

    // {
    //
    //     function fn(a,b){
    //         "use strict";
    //         console.log(this,a,b);
    //     }
    //     const obj = {
    //         userName:"zhangsan"
    //     }
    //     // 第一个参数指定fn中的this指向。其余的参数为传递的值
    //     // fn.call(this,1,2);// window
    //     // fn.call(null,1,2);// window
    //     // fn.call(undefined,1,2);// window
    //     // fn.call(1,1,2);// 1的包装对象
    //     // fn.call("1",1,2);// "1"的包装对象
    //     // fn.call(true,1,2);// true的包装对象
    //     // fn.call(obj,1,2);// obj
    //     // fn.call(function(){},1,2);// function(){}
    //     // fn.call([],1,2);// []
    //     // fn.call({},1,2);// {}
    //
    //     // 开启严格模式
    //     fn.call(this,1,2);// window
    //     fn.call(null,1,2);// null
    //     fn.call(undefined,1,2);// undefined
    //     fn.call(1,1,2);// 1
    //     fn.call("abc",1,2);// abc
    //     fn.call(true,1,2);// true
    //     fn.call(obj,1,2);// obj
    //     fn.call(function(){},1,2);// function(){}
    //     fn.call([],1,2);// []
    //     fn.call({},1,2);// {}
    //
    // }

    {
        // apply与call唯一的区别是传递参数
        {

            function fn(a,b){
                "use strict";
                console.log(this,a,b);
            }
            const obj = {
                userName:"zhangsan"
            }
            // 第一个参数指定fn中的this指向。其余的参数为传递的值
            // fn.apply(this,[1,2]);// window
            // fn.apply(null,[1,2]);// window
            // fn.apply(undefined,[1,2]);// window
            // fn.apply(1,[1,2]);// 1的包装对象
            // fn.apply("1",[1,2]);// "1"的包装对象
            // fn.apply(true,[1,2]);// true的包装对象
            // fn.apply(obj,[1,2]);// obj
            // fn.apply(function(){},[1,2]);// function(){}
            // fn.apply([],[1,2]);// []
            // fn.apply({},[1,2]);// {}

            // 开启严格模式
            // fn.apply(this,[1,2]);// window
            // fn.apply(null,[1,2]);// null
            // fn.apply(undefined,[1,2]);// undefined
            // fn.apply(1,[1,2]);// 1
            // fn.apply("abc",[1,2]);// abc
            // fn.apply(true,[1,2]);// true
            // fn.apply(obj,[1,2]);// obj
            // fn.apply(function(){},[1,2]);// function(){}
            // fn.apply([],[1,2]);// []
            // fn.apply({},[1,2]);// {}

        }
    }
    {
        // bind:1- 可以绑定this 2- 可以绑定参数
        function fn(a,b,c,d){
            console.log("fn",this,a,b,c,d)
        }
        // const fn2 = fn.bind();
        // console.log(fn === fn2);// false
        // fn.bind()();// window undefined undefined undefined undefined
        // fn.bind(this,1,2)();// window 1 2 undefined undefined
        // fn.bind(this,1,2,3)();// window 1 2 3 undefined
        // fn.bind(this,1,2,3)(4);// window 1 2 3 4
        // fn.bind(this,1,2)(4,100);// window 1 2 4 100

        // const fn2 = fn.bind(this,1,2);
        // fn2();// window 1 2 undefined undefined
        // fn2(3);// window 1 2 3 undefined
        // fn2(3,4);// window 1 2 3 4

        // fn.bind(null)(1,2,3,4);// window 1 2 3 4
    }

    // * **call 、bind 、 apply 传参情况**
    // * call 的参数是直接放进去的，第二第三第 n 个参数全都用逗号分隔，直接放到后面
    // * apply 的所有参数都必须放在一个数组里面传进去
    // * bind 除了返回是函数以外，它的参数和 call 一样
</script>
</html>